

<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  
  <title>ceph-mgr 模块开发指南 &mdash; Ceph Documentation</title>
  

  
  <link rel="stylesheet" href="../../_static/ceph.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/ceph.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/graphviz.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/css/custom.css" type="text/css" />

  
  

  
  

  

  
  <!--[if lt IE 9]>
    <script src="../../_static/js/html5shiv.min.js"></script>
  <![endif]-->
  
    
      <script type="text/javascript" id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
        <script src="../../_static/jquery.js"></script>
        <script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
        <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
        <script src="../../_static/doctools.js"></script>
        <script src="../../_static/sphinx_highlight.js"></script>
    
    <script type="text/javascript" src="../../_static/js/theme.js"></script>

    
    <link rel="index" title="Index" href="../../genindex/" />
    <link rel="search" title="Search" href="../../search/" />
    <link rel="next" title="ceph-mgr orchestrator 模块" href="../orchestrator_modules/" />
    <link rel="prev" title="ceph-mgr 管理员指南" href="../administrator/" /> 
</head>

<body class="wy-body-for-nav">

   
  <header class="top-bar">
    <div role="navigation" aria-label="Page navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="../../" class="icon icon-home" aria-label="Home"></a></li>
          <li class="breadcrumb-item"><a href="../">Ceph 管理器守护进程</a></li>
      <li class="breadcrumb-item active">ceph-mgr 模块开发指南</li>
      <li class="wy-breadcrumbs-aside">
            <a href="../../_sources/mgr/modules.rst.txt" rel="nofollow"> View page source</a>
      </li>
  </ul>
  <hr/>
</div>
  </header>
  <div class="wy-grid-for-nav">
    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search"  style="background: #eee" >
          

          
            <a href="../../" class="icon icon-home"> Ceph
          

          
          </a>

          

          
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../../search/" method="get">
    <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

          
        </div>

        
        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          
            
            
              
            
            
              <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../../start/">Ceph 简介</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../install/">安装 Ceph</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../cephadm/">Cephadm</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../rados/">Ceph 存储集群</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../cephfs/">Ceph 文件系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../rbd/">Ceph 块设备</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../radosgw/">Ceph 对象网关</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../">Ceph 管理器守护进程</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="../administrator/">安装和配置</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">模块编程</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#id1">创建模块</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id2">安装模块</a></li>
<li class="toctree-l3"><a class="reference internal" href="#mgr-module-dev-logging">日志记录</a></li>
<li class="toctree-l3"><a class="reference internal" href="#exposing-commands">Exposing commands</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#the-clicommand-approach">The CLICommand approach</a></li>
<li class="toctree-l4"><a class="reference internal" href="#the-commands-approach">The COMMANDS Approach</a></li>
<li class="toctree-l4"><a class="reference internal" href="#responses-and-formatting">Responses and Formatting</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id4">配置选项</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_module_option"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_module_option()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.set_module_option"><code class="docutils literal notranslate"><span class="pre">MgrModule.set_module_option()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_localized_module_option"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_localized_module_option()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.set_localized_module_option"><code class="docutils literal notranslate"><span class="pre">MgrModule.set_localized_module_option()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#kv-store">KV store</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_store"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_store()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.set_store"><code class="docutils literal notranslate"><span class="pre">MgrModule.set_store()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_localized_store"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_localized_store()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.set_localized_store"><code class="docutils literal notranslate"><span class="pre">MgrModule.set_localized_store()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_store_prefix"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_store_prefix()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id5">访问集群数据</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get"><code class="docutils literal notranslate"><span class="pre">MgrModule.get()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_server"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_server()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.list_servers"><code class="docutils literal notranslate"><span class="pre">MgrModule.list_servers()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_metadata"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_metadata()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_daemon_status"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_daemon_status()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_perf_schema"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_perf_schema()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_counter"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_counter()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_mgr_id"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_mgr_id()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.get_daemon_health_metrics"><code class="docutils literal notranslate"><span class="pre">MgrModule.get_daemon_health_metrics()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id6">暴露给健康检查</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.set_health_checks"><code class="docutils literal notranslate"><span class="pre">MgrModule.set_health_checks()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id7">监视器挂了怎么办？</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.have_mon_connection"><code class="docutils literal notranslate"><span class="pre">MgrModule.have_mon_connection()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id8">在模块不可运行时报告</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.can_run"><code class="docutils literal notranslate"><span class="pre">MgrModule.can_run()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id9">发出命令</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.send_command"><code class="docutils literal notranslate"><span class="pre">MgrModule.send_command()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id10">接收通知</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.notify"><code class="docutils literal notranslate"><span class="pre">MgrModule.notify()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#rados-cephfs">访问 RADOS 或 CephFS</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id11">备用模式的实现</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id12">模块间通信</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#mgr_module.MgrModule.remote"><code class="docutils literal notranslate"><span class="pre">MgrModule.remote()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#id13">干净地关闭</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id14">局限性</a></li>
<li class="toctree-l3"><a class="reference internal" href="#debugging">Debugging</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id15">还有未竟事宜否？</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../orchestrator_modules/">编写 orchestrator 插件</a></li>
<li class="toctree-l2"><a class="reference internal" href="../dashboard/">仪表盘模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ceph_api/">Ceph RESTful API</a></li>
<li class="toctree-l2"><a class="reference internal" href="../alerts/">Alerts 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../diskprediction/">DiskPrediction 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../localpool/">localpool 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../prometheus/">Prometheus 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../influx/">Influx 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../hello/">Hello 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../telegraf/">Telegraf 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../telemetry/">Telemetry 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../iostat/">Iostat 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../crash/">Crash 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../insights/">Insights 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../orchestrator/">Orchestrator 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../rook/">Rook 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../rgw/">RGW 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../mds_autoscaler/">MDS Autoscaler 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../nfs/">NFS 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../smb/">SMB module</a></li>
<li class="toctree-l2"><a class="reference internal" href="../progress/">Progress 模块</a></li>
<li class="toctree-l2"><a class="reference internal" href="../cli_api/">CLI API 命令模块</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../dashboard/">Ceph 仪表盘</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../monitoring/">监控概览</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/">API 文档</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../architecture/">体系结构</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../dev/developer_guide/">开发者指南</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../dev/internals/">Ceph 内幕</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../governance/">项目管理</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../foundation/">Ceph 基金会</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../ceph-volume/">ceph-volume</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../releases/general/">Ceph 版本（总目录）</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../releases/">Ceph 版本（索引）</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../security/">Security</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../hardware-monitoring/">硬件监控</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../glossary/">Ceph 术语</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../jaegertracing/">Tracing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../translation_cn/">中文版翻译资源</a></li>
</ul>

            
          
        </div>
        
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" aria-label="top navigation">
        
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="../../">Ceph</a>
        
      </nav>


      <div class="wy-nav-content">
        
        <div class="rst-content">
        
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
            
<div id="dev-warning" class="admonition note">
  <p class="first admonition-title">Notice</p>
  <p class="last">This document is for a development version of Ceph.</p>
</div>
  <div id="docubetter" align="right" style="padding: 5px; font-weight: bold;">
    <a href="https://pad.ceph.com/p/Report_Documentation_Bugs">Report a Documentation Bug</a>
  </div>

  
  <section id="ceph-mgr">
<span id="mgr-module-dev"></span><h1>ceph-mgr 模块开发指南<a class="headerlink" href="#ceph-mgr" title="Permalink to this heading"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>这是开发者文档，所述的 Ceph 内部机制仅供 ceph-mgr 模块开发者使用。</p>
</div>
<section id="id1">
<h2>创建模块<a class="headerlink" href="#id1" title="Permalink to this heading"></a></h2>
<p>在 pybind/mgr/ 目录下，创建一个 python 模块，在此模块内创建一个继承 <code class="docutils literal notranslate"><span class="pre">MgrModule</span></code> 的类。为了让 ceph-mgr 能探测到你的模块，你的目录必须包含一个名为 <cite>module.py</cite> 的文件。</p>
<p>需要覆盖的、最重要的方法有：</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">serve</span></code> 成员函数，用于服务器类型的模块，
此函数应该永远阻塞；</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">notify</span></code> 成员函数，如果你的模块想对新的集群数据有所动作；</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">handle_command</span></code> 成员函数，如果你的模块要暴露 CLI 命令。
但是，这个暴露命令的方法废弃了。
更多详情见 <a class="reference internal" href="#mgr-module-exposing-commands"><span class="std std-ref">Exposing commands</span></a> 。</p></li>
</ul>
<p>Some modules interface with external orchestrators to deploy
Ceph services.  These also inherit from <code class="docutils literal notranslate"><span class="pre">Orchestrator</span></code>, which adds
additional methods to the base <code class="docutils literal notranslate"><span class="pre">MgrModule</span></code> class.  See
<a class="reference internal" href="../orchestrator_modules/#orchestrator-modules"><span class="std std-ref">Orchestrator modules</span></a> for more on
creating these modules.</p>
</section>
<section id="id2">
<h2>安装模块<a class="headerlink" href="#id2" title="Permalink to this heading"></a></h2>
<p>你自己的模块放入 <code class="docutils literal notranslate"><span class="pre">mgr</span> <span class="pre">module</span> <span class="pre">path</span></code> 配置选项所指的路径后，可以用 <code class="docutils literal notranslate"><span class="pre">ceph</span> <span class="pre">mgr</span> <span class="pre">module</span> <span class="pre">enable</span></code> 命令启用它：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ceph</span> <span class="n">mgr</span> <span class="n">module</span> <span class="n">enable</span> <span class="n">mymodule</span>
</pre></div>
</div>
<p>请注意， MgrModule 接口不稳定，所以 Ceph 树以外维护的模块用于较新或较低版本的 Ceph 时可能很容易崩溃。</p>
</section>
<section id="mgr-module-dev-logging">
<span id="id3"></span><h2>日志记录<a class="headerlink" href="#mgr-module-dev-logging" title="Permalink to this heading"></a></h2>
<p>Logging in Ceph manager modules is done as in any other Python program. Just
import the <code class="docutils literal notranslate"><span class="pre">logging</span></code> package and get a logger instance with the
<code class="docutils literal notranslate"><span class="pre">logging.getLogger</span></code> function.</p>
<p>Each module has a <code class="docutils literal notranslate"><span class="pre">log_level</span></code> option that specifies the current Python
logging level of the module.
To change or query the logging level of the module use the following Ceph
commands:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ceph</span> <span class="n">config</span> <span class="n">get</span> <span class="n">mgr</span> <span class="n">mgr</span><span class="o">/&lt;</span><span class="n">module_name</span><span class="o">&gt;/</span><span class="n">log_level</span>
<span class="n">ceph</span> <span class="n">config</span> <span class="nb">set</span> <span class="n">mgr</span> <span class="n">mgr</span><span class="o">/&lt;</span><span class="n">module_name</span><span class="o">&gt;/</span><span class="n">log_level</span> <span class="o">&lt;</span><span class="n">info</span><span class="o">|</span><span class="n">debug</span><span class="o">|</span><span class="n">critical</span><span class="o">|</span><span class="n">error</span><span class="o">|</span><span class="n">warning</span><span class="o">|&gt;</span>
</pre></div>
</div>
<p>The logging level used upon the module’s start is determined by the current
logging level of the mgr daemon, unless if the <code class="docutils literal notranslate"><span class="pre">log_level</span></code> option was
previously set with the <code class="docutils literal notranslate"><span class="pre">config</span> <span class="pre">set</span> <span class="pre">...</span></code> command. The mgr daemon logging
level is mapped to the module python logging level as follows:</p>
<ul class="simple">
<li><p>&lt;= 0 is CRITICAL</p></li>
<li><p>&lt;= 1 is WARNING</p></li>
<li><p>&lt;= 4 is INFO</p></li>
<li><p>&lt;= +inf is DEBUG</p></li>
</ul>
<p>We can unset the module log level and fallback to the mgr daemon logging level
by running the following command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ceph</span> <span class="n">config</span> <span class="nb">set</span> <span class="n">mgr</span> <span class="n">mgr</span><span class="o">/&lt;</span><span class="n">module_name</span><span class="o">&gt;/</span><span class="n">log_level</span> <span class="s1">&#39;&#39;</span>
</pre></div>
</div>
<p>By default, modules’ logging messages are processed by the Ceph logging layer
where they will be recorded in the mgr daemon’s log file.
But it’s also possible to send a module’s logging message to it’s own file.</p>
<p>The module’s log file will be located in the same directory as the mgr daemon’s
log file with the following name pattern:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">mgr_daemon_log_file_name</span><span class="o">&gt;.&lt;</span><span class="n">module_name</span><span class="o">&gt;.</span><span class="n">log</span>
</pre></div>
</div>
<p>To enable the file logging on a module use the following command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ceph</span> <span class="n">config</span> <span class="nb">set</span> <span class="n">mgr</span> <span class="n">mgr</span><span class="o">/&lt;</span><span class="n">module_name</span><span class="o">&gt;/</span><span class="n">log_to_file</span> <span class="n">true</span>
</pre></div>
</div>
<p>When the module’s file logging is enabled, module’s logging messages stop
being written to the mgr daemon’s log file and are only written to the
module’s log file.</p>
<p>It’s also possible to check the status and disable the file logging with the
following commands:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ceph</span> <span class="n">config</span> <span class="n">get</span> <span class="n">mgr</span> <span class="n">mgr</span><span class="o">/&lt;</span><span class="n">module_name</span><span class="o">&gt;/</span><span class="n">log_to_file</span>
<span class="n">ceph</span> <span class="n">config</span> <span class="nb">set</span> <span class="n">mgr</span> <span class="n">mgr</span><span class="o">/&lt;</span><span class="n">module_name</span><span class="o">&gt;/</span><span class="n">log_to_file</span> <span class="n">false</span>
</pre></div>
</div>
</section>
<section id="exposing-commands">
<span id="mgr-module-exposing-commands"></span><h2>Exposing commands<a class="headerlink" href="#exposing-commands" title="Permalink to this heading"></a></h2>
<p>There are two approaches for exposing a command. The first method involves using
the <code class="docutils literal notranslate"><span class="pre">&#64;CLICommand</span></code> decorator to decorate the methods needed to handle a command.
The second method uses a <code class="docutils literal notranslate"><span class="pre">COMMANDS</span></code> attribute defined for the module class.</p>
<section id="the-clicommand-approach">
<h3>The CLICommand approach<a class="headerlink" href="#the-clicommand-approach" title="Permalink to this heading"></a></h3>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@CLICommand</span><span class="p">(</span><span class="s1">&#39;antigravity send to blackhole&#39;</span><span class="p">,</span>
            <span class="n">perm</span><span class="o">=</span><span class="s1">&#39;rw&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">send_to_blackhole</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">oid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">blackhole</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">inbuf</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&#39;&#39;&#39;</span>
<span class="sd">    Send the specified object to black hole</span>
<span class="sd">    &#39;&#39;&#39;</span>
    <span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">find_object</span><span class="p">(</span><span class="n">oid</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">HandleCommandResult</span><span class="p">(</span><span class="o">-</span><span class="n">errno</span><span class="o">.</span><span class="n">ENOENT</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;object &#39;</span><span class="si">{</span><span class="n">oid</span><span class="si">}</span><span class="s2">&#39; not found&quot;</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">blackhole</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">inbuf</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">location</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">blackhole</span><span class="p">,</span> <span class="n">passphrase</span><span class="o">=</span><span class="n">inbuf</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">HandleCommandResult</span><span class="p">(</span><span class="o">-</span><span class="n">errno</span><span class="o">.</span><span class="n">EINVAL</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="s1">&#39;unable to decrypt location&#39;</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">location</span> <span class="o">=</span> <span class="n">blackhole</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">send_object_to</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">location</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">HandleCommandResult</span><span class="p">(</span><span class="n">stdout</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;the black hole swallowed &#39;</span><span class="si">{</span><span class="n">oid</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The first parameter passed to <code class="docutils literal notranslate"><span class="pre">CLICommand</span></code> is the “name” of the command.
Since there are lots of commands in Ceph, we tend to group related commands
with a common prefix. In this case, “antigravity” is used for this purpose.
As the author is probably designing a module which is also able to launch
rockets into the deep space.</p>
<p>The <a class="reference external" href="https://www.python.org/dev/peps/pep-0484/">type annotations</a> for the
method parameters are mandatory here, so the usage of the command can be
properly reported to the <code class="docutils literal notranslate"><span class="pre">ceph</span></code> CLI, and the manager daemon can convert
the serialized command parameters sent by the clients to the expected type
before passing them to the handler method. With properly implemented types,
one can also perform some sanity checks against the parameters!</p>
<p>The names of the parameters are part of the command interface, so please
try to take the backward compatibility into consideration when changing
them. But you <strong>cannot</strong> change name of <code class="docutils literal notranslate"><span class="pre">inbuf</span></code> parameter, it is used
to pass the content of the file specified by <code class="docutils literal notranslate"><span class="pre">ceph</span> <span class="pre">--in-file</span></code> option.</p>
<p>The docstring of the method is used for the description of the command.</p>
<p>The manager daemon cooks the usage of the command from these ingredients,
like:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">antigravity</span> <span class="n">send</span> <span class="n">to</span> <span class="n">blackhole</span> <span class="o">&lt;</span><span class="n">oid</span><span class="o">&gt;</span> <span class="p">[</span><span class="o">&lt;</span><span class="n">blackhole</span><span class="o">&gt;</span><span class="p">]</span>  <span class="n">Send</span> <span class="n">the</span> <span class="n">specified</span> <span class="nb">object</span> <span class="n">to</span> <span class="n">black</span> <span class="n">hole</span>
</pre></div>
</div>
<p>as part of the output of <code class="docutils literal notranslate"><span class="pre">ceph</span> <span class="pre">--help</span></code>.</p>
<p>In addition to <code class="docutils literal notranslate"><span class="pre">&#64;CLICommand</span></code>, you could also use <code class="docutils literal notranslate"><span class="pre">&#64;CLIReadCommand</span></code> or
<code class="docutils literal notranslate"><span class="pre">&#64;CLIWriteCommand</span></code> if your command only requires read permissions or
write permissions respectively.</p>
</section>
<section id="the-commands-approach">
<h3>The COMMANDS Approach<a class="headerlink" href="#the-commands-approach" title="Permalink to this heading"></a></h3>
<p>This method uses the <code class="docutils literal notranslate"><span class="pre">COMMANDS</span></code> class attribute of your module to define
a list of dicts like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">COMMANDS</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">{</span>
        <span class="s2">&quot;cmd&quot;</span><span class="p">:</span> <span class="s2">&quot;foobar name=myarg,type=CephString&quot;</span><span class="p">,</span>
        <span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Do something awesome&quot;</span><span class="p">,</span>
        <span class="s2">&quot;perm&quot;</span><span class="p">:</span> <span class="s2">&quot;rw&quot;</span><span class="p">,</span>
        <span class="c1"># optional:</span>
        <span class="s2">&quot;poll&quot;</span><span class="p">:</span> <span class="s2">&quot;true&quot;</span>
    <span class="p">}</span>
<span class="p">]</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">cmd</span></code> part of each entry is parsed in the same way as internal
Ceph mon and admin socket commands (see mon/MonCommands.h in
the Ceph source for examples). Note that the “poll” field is optional,
and is set to False by default; this indicates to the <code class="docutils literal notranslate"><span class="pre">ceph</span></code> CLI
that it should call this command repeatedly and output results (see
<code class="docutils literal notranslate"><span class="pre">ceph</span> <span class="pre">-h</span></code> and its <code class="docutils literal notranslate"><span class="pre">--period</span></code> option).</p>
<p>Each command is expected to return a tuple <code class="docutils literal notranslate"><span class="pre">(retval,</span> <span class="pre">stdout,</span> <span class="pre">stderr)</span></code>.
<code class="docutils literal notranslate"><span class="pre">retval</span></code> is an integer representing a libc error code (e.g. EINVAL,
EPERM, or 0 for no error), <code class="docutils literal notranslate"><span class="pre">stdout</span></code> is a string containing any
non-error output, and <code class="docutils literal notranslate"><span class="pre">stderr</span></code> is a string containing any progress or
error explanation output.  Either or both of the two strings may be empty.</p>
<p>Implement the <code class="docutils literal notranslate"><span class="pre">handle_command</span></code> function to respond to the commands
when they are sent:</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.handle_command">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">handle_command</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">inbuf</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cmd</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.handle_command" title="Permalink to this definition"></a></dt>
<dd><p>Called by ceph-mgr to request the plugin to handle one
of the commands that it declared in self.COMMANDS</p>
<p>Return a status code, an output buffer, and an
output string.  The output buffer is for data results,
the output string is for informative text.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inbuf</strong> (<em>str</em>) -- content of any “-i &lt;file&gt;” supplied to ceph cli</p></li>
<li><p><strong>cmd</strong> (<em>dict</em>) -- from Ceph’s cmdmap_t</p></li>
</ul>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Union</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">HandleCommandResult</span></code>, <code class="xref py py-data docutils literal notranslate"><span class="pre">Tuple</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>]]</p>
</dd>
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>HandleCommandResult or a 3-tuple of (int, str, str)</p>
</dd>
</dl>
</dd></dl>

</section>
<section id="responses-and-formatting">
<h3>Responses and Formatting<a class="headerlink" href="#responses-and-formatting" title="Permalink to this heading"></a></h3>
<p>Functions that handle manager commands are expected to return a three element
tuple with the type signature <code class="docutils literal notranslate"><span class="pre">Tuple[int,</span> <span class="pre">str,</span> <span class="pre">str]</span></code>. The first element is a
return value/error code, where zero indicates no error and a negative <a class="reference external" href="https://man7.org/linux/man-pages/man3/errno.3.html">errno</a>
is typically used for error conditions.  The second element corresponds to the
command’s “output”. The third element corresponds to the command’s “error
output” (akin to stderr) and is frequently used to report textual error details
when the return code is non-zero. The <code class="docutils literal notranslate"><span class="pre">mgr_module.HandleCommandResult</span></code> type
can also be used in lieu of a response tuple.</p>
<p>When the implementation of a command raises an exception one of two possible
approaches to handling the exception exist. First, the command function can do
nothing and let the exception bubble up to the manager.  When this happens the
manager will automatically set a return code to -EINVAL and record a trace-back
in the error output. This trace-back can be very long in some cases. The second
approach is to handle an exception within a try-except block and convert the
exception to an error code that better fits the exception (converting a
KeyError to -ENOENT, for example).  In this case the error output may also be
set to something more specific and actionable by the one calling the command.</p>
<p>In many cases, especially in more recent versions of Ceph, manager commands are
designed to return structured output to the caller. Structured output includes
machine-parsable data such as JSON, YAML, XML, etc. JSON is the most common
structured output format returned by manager commands. As of Ceph Reef, there
are a number of new decorators available from the <code class="docutils literal notranslate"><span class="pre">object_format</span></code> module that
help manage formatting output and handling exceptions automatically.  The
intent is that most of the implementation of a manager command can be written in
an idiomatic (aka “Pythonic”) style and the decorators will take care of most of
the work needed to format the output and return manager response tuples.</p>
<p>In most cases, net new code should use the <code class="docutils literal notranslate"><span class="pre">Responder</span></code> decorator. Example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@CLICommand</span><span class="p">(</span><span class="s1">&#39;antigravity list wormholes&#39;</span><span class="p">,</span> <span class="n">perm</span><span class="o">=</span><span class="s1">&#39;r&#39;</span><span class="p">)</span>
<span class="nd">@Responder</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">list_wormholes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">oid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">details</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]:</span>
<span class="w">    </span><span class="sd">&#39;&#39;&#39;List wormholes associated with the supplied oid.</span>
<span class="sd">    &#39;&#39;&#39;</span>
    <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">open_wormhole_db</span><span class="p">()</span> <span class="k">as</span> <span class="n">db</span><span class="p">:</span>
        <span class="n">wormholes</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">oid</span><span class="o">=</span><span class="n">oid</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">details</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">name</span><span class="p">}</span> <span class="k">for</span> <span class="n">wh</span> <span class="ow">in</span> <span class="n">wormholes</span><span class="p">]</span>
    <span class="k">return</span> <span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s1">&#39;age&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">get_age</span><span class="p">(),</span> <span class="s1">&#39;destination&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">dest</span><span class="p">}</span>
            <span class="k">for</span> <span class="n">wh</span> <span class="ow">in</span> <span class="n">wormholes</span><span class="p">]</span>
</pre></div>
</div>
<section id="formatting">
<h4>Formatting<a class="headerlink" href="#formatting" title="Permalink to this heading"></a></h4>
<p>The <code class="docutils literal notranslate"><span class="pre">Responder</span></code> decorator automatically takes care of converting Python
objects into a response tuple with formatted output. By default, this decorator
can automatically return JSON and YAML. When invoked from the command line the
<code class="docutils literal notranslate"><span class="pre">--format</span></code> flag can be used to select the response format. If left
unspecified, JSON will be returned. The automatic formatting can be applied to
any basic Python type: lists, dicts, str, int, etc. Other objects can be
formatted automatically if they meet the <code class="docutils literal notranslate"><span class="pre">SimpleDataProvider</span></code> protocol - they
provide a <code class="docutils literal notranslate"><span class="pre">to_simplified</span></code> method. The <code class="docutils literal notranslate"><span class="pre">to_simplified</span></code> function must return
a simplified representation of the object made out of basic types.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyCleverObject</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">to_simplified</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
        <span class="c1"># returns a python object(s) made up from basic types</span>
        <span class="k">return</span> <span class="p">{</span><span class="s2">&quot;gravitons&quot;</span><span class="p">:</span> <span class="mi">999</span><span class="p">,</span> <span class="s2">&quot;tachyons&quot;</span><span class="p">:</span> <span class="mi">404</span><span class="p">}</span>

<span class="nd">@CLICommand</span><span class="p">(</span><span class="s1">&#39;antigravity list wormholes&#39;</span><span class="p">,</span> <span class="n">perm</span><span class="o">=</span><span class="s1">&#39;r&#39;</span><span class="p">)</span>
<span class="nd">@Responder</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">list_wormholes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">oid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">details</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">MyCleverObject</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&#39;&#39;&#39;List wormholes associated with the supplied oid.</span>
<span class="sd">    &#39;&#39;&#39;</span>
    <span class="o">...</span>
</pre></div>
</div>
<p>The behavior of the automatic output formatting can be customized and extednted
to other types of formatting (XML, Plain Text, etc). As this is a complex
topic, please refer to the module documentation for the <code class="docutils literal notranslate"><span class="pre">object_format</span></code>
module.</p>
</section>
<section id="error-handling">
<h4>Error Handling<a class="headerlink" href="#error-handling" title="Permalink to this heading"></a></h4>
<p>Additionally, the <code class="docutils literal notranslate"><span class="pre">Responder</span></code> decorator can automatically handle converting
some  exceptions into response tuples. Any raised exception inheriting from
<code class="docutils literal notranslate"><span class="pre">ErrorResponseBase</span></code> will be automatically converted into a response tuple.
The common approach will be to use <code class="docutils literal notranslate"><span class="pre">ErrorResponse</span></code>, an exception type that
can be used directly and has arguments for the error output and return value or
it can be constructed from an existing exception using the <code class="docutils literal notranslate"><span class="pre">wrap</span></code>
classmethod. The wrap classmethod will automatically use the exception text and
if available the <code class="docutils literal notranslate"><span class="pre">errno</span></code> property of other exceptions.</p>
<p>Converting our previous example to use this exception handling approach:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@CLICommand</span><span class="p">(</span><span class="s1">&#39;antigravity list wormholes&#39;</span><span class="p">,</span> <span class="n">perm</span><span class="o">=</span><span class="s1">&#39;r&#39;</span><span class="p">)</span>
<span class="nd">@Responder</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">list_wormholes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">oid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">details</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]:</span>
<span class="w">    </span><span class="sd">&#39;&#39;&#39;List wormholes associated with the supplied oid.</span>
<span class="sd">    &#39;&#39;&#39;</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">open_wormhole_db</span><span class="p">()</span> <span class="k">as</span> <span class="n">db</span><span class="p">:</span>
            <span class="n">wormholes</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">oid</span><span class="o">=</span><span class="n">oid</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">UnknownOIDError</span><span class="p">:</span>
         <span class="k">raise</span> <span class="n">ErrorResponse</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unknown oid: </span><span class="si">{</span><span class="n">oid</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">return_value</span><span class="o">=-</span><span class="n">errno</span><span class="o">.</span><span class="n">ENOENT</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">WormholeDBError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
        <span class="k">raise</span> <span class="n">ErrorResponse</span><span class="o">.</span><span class="n">wrap</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">details</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">name</span><span class="p">}</span> <span class="k">for</span> <span class="n">wh</span> <span class="ow">in</span> <span class="n">wormholes</span><span class="p">]</span>
    <span class="k">return</span> <span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s1">&#39;age&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">get_age</span><span class="p">(),</span> <span class="s1">&#39;destination&#39;</span><span class="p">:</span> <span class="n">wh</span><span class="o">.</span><span class="n">dest</span><span class="p">}</span>
            <span class="k">for</span> <span class="n">wh</span> <span class="ow">in</span> <span class="n">wormholes</span><span class="p">]</span>
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Because the decorator can not determine the difference between a
programming mistake and an expected error condition it does not try to
catch all exceptions.</p>
</div>
</section>
<section id="additional-decorators">
<h4>Additional Decorators<a class="headerlink" href="#additional-decorators" title="Permalink to this heading"></a></h4>
<p>The <code class="docutils literal notranslate"><span class="pre">object_format</span></code> module provides additional decorators to complement
<code class="docutils literal notranslate"><span class="pre">Responder</span></code> but for cases where <code class="docutils literal notranslate"><span class="pre">Responder</span></code> is insufficient or too “heavy
weight”.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">ErrorResponseHandler</span></code> decorator exists for cases where you <em>must</em> still
return a manager response tuple but want to handle errors as exceptions (as in
typical Python code). In short, it works like <code class="docutils literal notranslate"><span class="pre">Responder</span></code> but only with
regards to exceptions. Just like <code class="docutils literal notranslate"><span class="pre">Responder</span></code> it handles exceptions that
inherit from <code class="docutils literal notranslate"><span class="pre">ErrorResponseBase</span></code>. This can be useful in cases where you need
to return raw data in the output. Example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@CLICommand</span><span class="p">(</span><span class="s1">&#39;antigravity dump config&#39;</span><span class="p">,</span> <span class="n">perm</span><span class="o">=</span><span class="s1">&#39;r&#39;</span><span class="p">)</span>
<span class="nd">@ErrorResponseHandler</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">dump_config</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">oid</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
<span class="w">    </span><span class="sd">&#39;&#39;&#39;Dump configuration</span>
<span class="sd">    &#39;&#39;&#39;</span>
    <span class="c1"># we have no control over what data is inside the blob!</span>
    <span class="k">try</span><span class="p">:</span>
         <span class="n">blob</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fetch_raw_config_blob</span><span class="p">(</span><span class="n">oid</span><span class="p">)</span>
         <span class="k">return</span> <span class="mi">0</span><span class="p">,</span> <span class="n">blob</span><span class="p">,</span> <span class="s1">&#39;&#39;</span>
    <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
         <span class="k">raise</span> <span class="n">ErrorResponse</span><span class="p">(</span><span class="s2">&quot;Blob does not exist&quot;</span><span class="p">,</span> <span class="n">return_value</span><span class="o">=-</span><span class="n">errno</span><span class="o">.</span><span class="n">ENOENT</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">EmptyResponder</span></code> decorator exists for cases where, on a success
condition, no output should be generated at all. If you used <code class="docutils literal notranslate"><span class="pre">Responder</span></code> and
default JSON formatting you may always see outputs like <code class="docutils literal notranslate"><span class="pre">{}</span></code> or <code class="docutils literal notranslate"><span class="pre">[]</span></code> if the
command completes without error. Instead, <code class="docutils literal notranslate"><span class="pre">EmptyResponder</span></code> helps you create
manager commands that obey the <a class="reference external" href="http://www.linfo.org/rule_of_silence.html">Rule of Silence</a> when the command has no
interesting output to emit on success. The functions that <code class="docutils literal notranslate"><span class="pre">EmptyResponder</span></code>
decorate should always return <code class="docutils literal notranslate"><span class="pre">None</span></code>. Like both <code class="docutils literal notranslate"><span class="pre">Responder</span></code> and
<code class="docutils literal notranslate"><span class="pre">ErrorResponseHandler</span></code> exceptions that inhert from <code class="docutils literal notranslate"><span class="pre">ErrorResponseBase</span></code> will
be automatically processed. Example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@CLICommand</span><span class="p">(</span><span class="s1">&#39;antigravity create wormhole&#39;</span><span class="p">,</span> <span class="n">perm</span><span class="o">=</span><span class="s1">&#39;rw&#39;</span><span class="p">)</span>
<span class="nd">@EmptyResponder</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">create_wormhole</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">oid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&#39;&#39;&#39;Create a new wormhole.</span>
<span class="sd">    &#39;&#39;&#39;</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">open_wormhole_db</span><span class="p">()</span> <span class="k">as</span> <span class="n">db</span><span class="p">:</span>
            <span class="n">wh</span> <span class="o">=</span> <span class="n">Wormhole</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
            <span class="n">db</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">oid</span><span class="o">=</span><span class="n">oid</span><span class="p">,</span> <span class="n">wormhole</span><span class="o">=</span><span class="n">wh</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">UnknownOIDError</span><span class="p">:</span>
        <span class="k">raise</span> <span class="n">ErrorResponse</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unknown oid: </span><span class="si">{</span><span class="n">oid</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">return_value</span><span class="o">=-</span><span class="n">errno</span><span class="o">.</span><span class="n">ENOENT</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">InvalidWormholeError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
        <span class="k">raise</span> <span class="n">ErrorResponse</span><span class="o">.</span><span class="n">wrap</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">WormholeDBError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
        <span class="k">raise</span> <span class="n">ErrorResponse</span><span class="o">.</span><span class="n">wrap</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
</pre></div>
</div>
</section>
</section>
</section>
<section id="id4">
<h2>配置选项<a class="headerlink" href="#id4" title="Permalink to this heading"></a></h2>
<p>Modules can load and store configuration options using the
<code class="docutils literal notranslate"><span class="pre">set_module_option</span></code> and <code class="docutils literal notranslate"><span class="pre">get_module_option</span></code> methods.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Use <code class="docutils literal notranslate"><span class="pre">set_module_option</span></code> and <code class="docutils literal notranslate"><span class="pre">get_module_option</span></code> to
manage user-visible configuration options that are not blobs (like
certificates). If you want to persist module-internal data or
binary configuration data consider using the <a class="reference internal" href="#kv-store">KV store</a>.</p>
</div>
<p>You must declare your available configuration options in the
<code class="docutils literal notranslate"><span class="pre">MODULE_OPTIONS</span></code> class attribute, like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">MODULE_OPTIONS</span> <span class="o">=</span> <span class="p">[</span>
    <span class="n">Option</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;my_option&quot;</span><span class="p">)</span>
<span class="p">]</span>
</pre></div>
</div>
<p>If you try to use set_module_option or get_module_option on options not declared
in <code class="docutils literal notranslate"><span class="pre">MODULE_OPTIONS</span></code>, an exception will be raised.</p>
<p>You may choose to provide setter commands in your module to perform
high level validation.  Users can also modify configuration using
the normal <cite>ceph config set</cite> command, where the configuration options
for a mgr module are named like <cite>mgr/&lt;module name&gt;/&lt;option&gt;</cite>.</p>
<p>If a configuration option is different depending on which node the mgr
is running on, then use <em>localized</em> configuration (
<code class="docutils literal notranslate"><span class="pre">get_localized_module_option</span></code>, <code class="docutils literal notranslate"><span class="pre">set_localized_module_option</span></code>).
This may be necessary for options such as what address to listen on.
Localized options may also be set externally with <code class="docutils literal notranslate"><span class="pre">ceph</span> <span class="pre">config</span> <span class="pre">set</span></code>,
where they key name is like <code class="docutils literal notranslate"><span class="pre">mgr/&lt;module</span> <span class="pre">name&gt;/&lt;mgr</span> <span class="pre">id&gt;/&lt;option&gt;</span></code></p>
<p>If you need to load and store data (e.g. something larger, binary, or multiline),
use the KV store instead of configuration options (see next section).</p>
<p>Hints for using config options:</p>
<ul class="simple">
<li><p>Reads are fast: ceph-mgr keeps a local in-memory copy, so in many cases
you can just do a get_module_option every time you use a option, rather than
copying it out into a variable.</p></li>
<li><p>Writes block until the value is persisted (i.e. round trip to the monitor),
but reads from another thread will see the new value immediately.</p></li>
<li><p>If a user has used <cite>config set</cite> from the command line, then the new
value will become visible to <cite>get_module_option</cite> immediately, although the
mon-&gt;mgr update is asynchronous, so <cite>config set</cite> will return a fraction
of a second before the new value is visible on the mgr.</p></li>
<li><p>To delete a config value (i.e. revert to default), just pass <code class="docutils literal notranslate"><span class="pre">None</span></code> to
set_module_option.</p></li>
</ul>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_module_option">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_module_option</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">default</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_module_option" title="Permalink to this definition"></a></dt>
<dd><p>Retrieve the value of a persistent configuration setting</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Union</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code>]</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.set_module_option">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">set_module_option</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">val</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.set_module_option" title="Permalink to this definition"></a></dt>
<dd><p>Set the value of a persistent configuration setting</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>key</strong> (<em>str</em>) -- </p>
</dd>
<dt class="field-even">Raises<span class="colon">:</span></dt>
<dd class="field-even"><p><strong>ValueError</strong> -- if <cite>val</cite> cannot be parsed or it is out of the specified range</p>
</dd>
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code></p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_localized_module_option">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_localized_module_option</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">default</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_localized_module_option" title="Permalink to this definition"></a></dt>
<dd><p>Retrieve localized configuration for this ceph-mgr instance</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Union</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code>]</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.set_localized_module_option">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">set_localized_module_option</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">val</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.set_localized_module_option" title="Permalink to this definition"></a></dt>
<dd><p>Set localized configuration for this ceph-mgr instance
:param str key:
:param str val:
:rtype: <code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code>
:return: str</p>
</dd></dl>

</section>
<section id="kv-store">
<h2>KV store<a class="headerlink" href="#kv-store" title="Permalink to this heading"></a></h2>
<p>Modules have access to a private (per-module) key value store, which
is implemented using the monitor’s “config-key” commands.  Use
the <code class="docutils literal notranslate"><span class="pre">set_store</span></code> and <code class="docutils literal notranslate"><span class="pre">get_store</span></code> methods to access the KV store from
your module.</p>
<p>The KV store commands work in a similar way to the configuration
commands.  Reads are fast, operating from a local cache.  Writes block
on persistence and do a round trip to the monitor.</p>
<p>This data can be access from outside of ceph-mgr using the
<code class="docutils literal notranslate"><span class="pre">ceph</span> <span class="pre">config-key</span> <span class="pre">[get|set]</span></code> commands.  Key names follow the same
conventions as configuration options.  Note that any values updated
from outside of ceph-mgr will not be seen by running modules until
the next restart.  Users should be discouraged from accessing module KV
data externally -- if it is necessary for users to populate data, modules
should provide special commands to set the data via the module.</p>
<p>Use the <code class="docutils literal notranslate"><span class="pre">get_store_prefix</span></code> function to enumerate keys within
a particular prefix (i.e. all keys starting with a particular substring).</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_store">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_store</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">default</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_store" title="Permalink to this definition"></a></dt>
<dd><p>Get a value from this module’s persistent key value store</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Optional</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>]</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.set_store">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">set_store</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">val</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.set_store" title="Permalink to this definition"></a></dt>
<dd><p>Set a value in this module’s persistent key value store.
If val is None, remove key from store</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code></p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_localized_store">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_localized_store</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">default</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_localized_store" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Optional</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>]</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.set_localized_store">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">set_localized_store</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">val</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.set_localized_store" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code></p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_store_prefix">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_store_prefix</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key_prefix</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_store_prefix" title="Permalink to this definition"></a></dt>
<dd><p>Retrieve a dict of KV store keys to values, where the keys
have the given prefix</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>key_prefix</strong> (<em>str</em>) -- </p>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>]</p>
</dd>
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>str</p>
</dd>
</dl>
</dd></dl>

</section>
<section id="id5">
<h2>访问集群数据<a class="headerlink" href="#id5" title="Permalink to this heading"></a></h2>
<p>Modules have access to the in-memory copies of the Ceph cluster’s
state that the mgr maintains.  Accessor functions as exposed
as members of MgrModule.</p>
<p>Calls that access the cluster or daemon state are generally going
from Python into native C++ routines.  There is some overhead to this,
but much less than for example calling into a REST API or calling into
an SQL database.</p>
<p>There are no consistency rules about access to cluster structures or
daemon metadata.  For example, an OSD might exist in OSDMap but
have no metadata, or vice versa.  On a healthy cluster these
will be very rare transient states, but modules should be written
to cope with the possibility.</p>
<p>Note that these accessors must not be called in the modules <code class="docutils literal notranslate"><span class="pre">__init__</span></code>
function. This will result in a circular locking exception.</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data_name</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get" title="Permalink to this definition"></a></dt>
<dd><p>Called by the plugin to fetch named cluster-wide objects from ceph-mgr.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>data_name</strong> (<em>str</em>) -- Valid things to fetch are osdmap_crush_map_text,
osd_map, osd_map_tree, osd_map_crush, config, mon_map, fs_map,
osd_metadata, pg_summary, io_rate, pg_dump, df, osd_stats,
health, mon_status, devices, device &lt;devid&gt;, pg_stats,
pool_stats, pg_ready, osd_ping_times, mgr_map, mgr_ips,
modified_config_options, service_map, mds_metadata,
have_local_config_map, osd_pool_stats, pg_status.</p>
</dd>
</dl>
<dl class="simple">
<dt>Note:</dt><dd><p>All these structures have their own JSON representations: experiment
or look at the C++ <code class="docutils literal notranslate"><span class="pre">dump()</span></code> methods to learn about them.</p>
</dd>
</dl>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Any</span></code></p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_server">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_server</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">hostname</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_server" title="Permalink to this definition"></a></dt>
<dd><p>Called by the plugin to fetch metadata about a particular hostname from
ceph-mgr.</p>
<p>This is information that ceph-mgr has gleaned from the daemon metadata
reported by daemons running on a particular server.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>hostname</strong> (<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>) -- a hostname</p>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-data docutils literal notranslate"><span class="pre">Union</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">List</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>]]]]</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.list_servers">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">list_servers</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.list_servers" title="Permalink to this definition"></a></dt>
<dd><p>Like <code class="docutils literal notranslate"><span class="pre">get_server</span></code>, but gives information about all servers (i.e. all
unique hostnames that have been mentioned in daemon metadata)</p>
<dl class="field-list simple">
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>a list of information about all servers</p>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p>list</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_metadata">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_metadata</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">svc_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">svc_id</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">default</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_metadata" title="Permalink to this definition"></a></dt>
<dd><p>Fetch the daemon metadata for a particular service.</p>
<p>ceph-mgr fetches metadata asynchronously, so are windows of time during
addition/removal of services where the metadata is not available to
modules.  <code class="docutils literal notranslate"><span class="pre">None</span></code> is returned if no metadata is available.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>svc_type</strong> (<em>str</em>) -- service type (e.g., ‘mds’, ‘osd’, ‘mon’)</p></li>
<li><p><strong>svc_id</strong> (<em>str</em>) -- service id. convert OSD integer IDs to strings when
calling this</p></li>
</ul>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p>dict, or None if no metadata found</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_daemon_status">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_daemon_status</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">svc_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">svc_id</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_daemon_status" title="Permalink to this definition"></a></dt>
<dd><p>Fetch the latest status for a particular service daemon.</p>
<p>This method may return <code class="docutils literal notranslate"><span class="pre">None</span></code> if no status information is
available, for example because the daemon hasn’t fully started yet.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>svc_type</strong> (<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>) -- string (e.g., ‘rgw’)</p></li>
<li><p><strong>svc_id</strong> (<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>) -- string</p></li>
</ul>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>]</p>
</dd>
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>dict, or None if the service is not found</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_perf_schema">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_perf_schema</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">svc_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">svc_name</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_perf_schema" title="Permalink to this definition"></a></dt>
<dd><p>Called by the plugin to fetch perf counter schema info.
svc_name can be nullptr, as can svc_type, in which case
they are wildcards</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>svc_type</strong> (<em>str</em>) -- </p></li>
<li><p><strong>svc_name</strong> (<em>str</em>) -- </p></li>
</ul>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-data docutils literal notranslate"><span class="pre">Union</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code>]]]]</p>
</dd>
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>list of dicts describing the counters requested</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_counter">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_counter</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">svc_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">svc_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">path</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_counter" title="Permalink to this definition"></a></dt>
<dd><p>Called by the plugin to fetch the latest performance counter data for a
particular counter on a particular service.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>svc_type</strong> (<em>str</em>) -- </p></li>
<li><p><strong>svc_name</strong> (<em>str</em>) -- </p></li>
<li><p><strong>path</strong> (<em>str</em>) -- a period-separated concatenation of the subsystem and the
counter name, for example “mds.inodes”.</p></li>
</ul>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">List</span></code>[<code class="xref py py-data docutils literal notranslate"><span class="pre">Tuple</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code>]]]</p>
</dd>
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>A dict of counter names to their values. each value is a list of
of two-tuples of (timestamp, value).  This may be empty if no data is
available.</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_mgr_id">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_mgr_id</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_mgr_id" title="Permalink to this definition"></a></dt>
<dd><p>Retrieve the name of the manager daemon where this plugin
is currently being executed (i.e. the active manager).</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></p>
</dd>
<dt class="field-even">Returns<span class="colon">:</span></dt>
<dd class="field-even"><p>str</p>
</dd>
</dl>
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.get_daemon_health_metrics">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">get_daemon_health_metrics</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.get_daemon_health_metrics" title="Permalink to this definition"></a></dt>
<dd><p>Get the list of health metrics per daemon. This includes SLOW_OPS health metrics
in MON and OSD daemons, and PENDING_CREATING_PGS health metrics for OSDs.</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">List</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>, <code class="xref py py-data docutils literal notranslate"><span class="pre">Any</span></code>]]]</p>
</dd>
</dl>
</dd></dl>

</section>
<section id="id6">
<h2>暴露给健康检查<a class="headerlink" href="#id6" title="Permalink to this heading"></a></h2>
<p>Modules can raise first class Ceph health checks, which will be reported
in the output of <code class="docutils literal notranslate"><span class="pre">ceph</span> <span class="pre">status</span></code> and in other places that report on the
cluster’s health.</p>
<p>If you use <code class="docutils literal notranslate"><span class="pre">set_health_checks</span></code> to report a problem, be sure to call
it again with an empty dict to clear your health check when the problem
goes away.</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.set_health_checks">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">set_health_checks</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">checks</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.set_health_checks" title="Permalink to this definition"></a></dt>
<dd><p>Set the module’s current map of health checks.  Argument is a
dict of check names to info, in this form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
  <span class="s1">&#39;CHECK_FOO&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;severity&#39;</span><span class="p">:</span> <span class="s1">&#39;warning&#39;</span><span class="p">,</span>           <span class="c1"># or &#39;error&#39;</span>
    <span class="s1">&#39;summary&#39;</span><span class="p">:</span> <span class="s1">&#39;summary string&#39;</span><span class="p">,</span>
    <span class="s1">&#39;count&#39;</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>                      <span class="c1"># quantify badness</span>
    <span class="s1">&#39;detail&#39;</span><span class="p">:</span> <span class="p">[</span> <span class="s1">&#39;list&#39;</span><span class="p">,</span> <span class="s1">&#39;of&#39;</span><span class="p">,</span> <span class="s1">&#39;detail&#39;</span><span class="p">,</span> <span class="s1">&#39;strings&#39;</span> <span class="p">],</span>
   <span class="p">},</span>
  <span class="s1">&#39;CHECK_BAR&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;severity&#39;</span><span class="p">:</span> <span class="s1">&#39;error&#39;</span><span class="p">,</span>
    <span class="s1">&#39;summary&#39;</span><span class="p">:</span> <span class="s1">&#39;bars are bad&#39;</span><span class="p">,</span>
    <span class="s1">&#39;detail&#39;</span><span class="p">:</span> <span class="p">[</span> <span class="s1">&#39;too hard&#39;</span> <span class="p">],</span>
  <span class="p">},</span>
<span class="p">}</span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>list</strong> -- dict of health check dicts</p>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code></p>
</dd>
</dl>
</dd></dl>

</section>
<section id="id7">
<h2>监视器挂了怎么办？<a class="headerlink" href="#id7" title="Permalink to this heading"></a></h2>
<p>The manager daemon gets much of its state (such as the cluster maps)
from the monitor.  If the monitor cluster is inaccessible, whichever
manager was active will continue to run, with the latest state it saw
still in memory.</p>
<p>However, if you are creating a module that shows the cluster state
to the user then you may well not want to mislead them by showing
them that out of date state.</p>
<p>To check if the manager daemon currently has a connection to
the monitor cluster, use this function:</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.have_mon_connection">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">have_mon_connection</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.have_mon_connection" title="Permalink to this definition"></a></dt>
<dd><p>Check whether this ceph-mgr daemon has an open connection
to a monitor.  If it doesn’t, then it’s likely that the
information we have about the cluster is out of date,
and/or the monitor cluster is down.</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code></p>
</dd>
</dl>
</dd></dl>

</section>
<section id="id8">
<h2>在模块不可运行时报告<a class="headerlink" href="#id8" title="Permalink to this heading"></a></h2>
<p>If your module cannot be run for any reason (such as a missing dependency),
then you can report that by implementing the <code class="docutils literal notranslate"><span class="pre">can_run</span></code> function.</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.can_run">
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">can_run</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.can_run" title="Permalink to this definition"></a></dt>
<dd><p>Implement this function to report whether the module’s dependencies
are met.  For example, if the module needs to import a particular
dependency to work, then use a try/except around the import at
file scope, and then report here if the import failed.</p>
<p>This will be called in a blocking way from the C++ code, so do not
do any I/O that could block in this function.</p>
<p>:return a 2-tuple consisting of a boolean and explanatory string</p>
<dl class="field-list simple">
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Tuple</span></code>[<code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>]</p>
</dd>
</dl>
</dd></dl>

<p>Note that this will only work properly if your module can always be imported:
if you are importing a dependency that may be absent, then do it in a
try/except block so that your module can be loaded far enough to use
<code class="docutils literal notranslate"><span class="pre">can_run</span></code> even if the dependency is absent.</p>
</section>
<section id="id9">
<h2>发出命令<a class="headerlink" href="#id9" title="Permalink to this heading"></a></h2>
<p>A non-blocking facility is provided for sending monitor commands
to the cluster.</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.send_command">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">send_command</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">result</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">svc_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">svc_id</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">command</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">tag</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">inbuf</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">one_shot</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.send_command" title="Permalink to this definition"></a></dt>
<dd><p>Called by the plugin to send a command to the mon
cluster.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>result</strong> (<em>CommandResult</em>) -- an instance of the <code class="docutils literal notranslate"><span class="pre">CommandResult</span></code>
class, defined in the same module as MgrModule.  This acts as a
completion and stores the output of the command.  Use
<code class="docutils literal notranslate"><span class="pre">CommandResult.wait()</span></code> if you want to block on completion.</p></li>
<li><p><strong>svc_type</strong> (<em>str</em>) -- </p></li>
<li><p><strong>svc_id</strong> (<em>str</em>) -- </p></li>
<li><p><strong>command</strong> (<em>str</em>) -- a JSON-serialized command.  This uses the same
format as the ceph command line, which is a dictionary of command
arguments, with the extra <code class="docutils literal notranslate"><span class="pre">prefix</span></code> key containing the command
name itself.  Consult MonCommands.h for available commands and
their expected arguments.</p></li>
<li><p><strong>tag</strong> (<em>str</em>) -- used for nonblocking operation: when a command
completes, the <code class="docutils literal notranslate"><span class="pre">notify()</span></code> callback on the MgrModule instance is
triggered, with notify_type set to “command”, and notify_id set to
the tag of the command.</p></li>
<li><p><strong>inbuf</strong> (<em>str</em>) -- input buffer for sending additional data.</p></li>
<li><p><strong>one_shot</strong> (<em>bool</em>) -- a keyword-only param to make the command abort
with EPIPE when the target resets or refuses to reconnect</p></li>
</ul>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code></p>
</dd>
</dl>
</dd></dl>

</section>
<section id="id10">
<h2>接收通知<a class="headerlink" href="#id10" title="Permalink to this heading"></a></h2>
<p>The manager daemon calls the <code class="docutils literal notranslate"><span class="pre">notify</span></code> function on all active modules
when certain important pieces of cluster state are updated, such as the
cluster maps.</p>
<p>The actual data is not passed into this function, rather it is a cue for
the module to go and read the relevant structure if it is interested.  Most
modules ignore most types of notification: to ignore a notification
simply return from this function without doing anything.</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.notify">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">notify</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">notify_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">notify_id</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.notify" title="Permalink to this definition"></a></dt>
<dd><p>Called by the ceph-mgr service to notify the Python plugin
that new state is available.  This method is <em>only</em> called for
notify_types that are listed in the NOTIFY_TYPES string list
member of the module class.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>notify_type</strong> (<code class="xref py py-class docutils literal notranslate"><span class="pre">NotifyType</span></code>) -- string indicating what kind of notification,
such as osd_map, mon_map, fs_map, mon_status,
health, pg_summary, command, service_map</p></li>
<li><p><strong>notify_id</strong> (<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>) -- string (may be empty) that optionally specifies
which entity is being notified about.  With
“command” notifications this is set to the tag
<code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">send_command</span></code>.</p></li>
</ul>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p><code class="xref py py-obj docutils literal notranslate"><span class="pre">None</span></code></p>
</dd>
</dl>
</dd></dl>

</section>
<section id="rados-cephfs">
<h2>访问 RADOS 或 CephFS<a class="headerlink" href="#rados-cephfs" title="Permalink to this heading"></a></h2>
<p>If you want to use the librados python API to access data stored in
the Ceph cluster, you can access the <code class="docutils literal notranslate"><span class="pre">rados</span></code> attribute of your
<code class="docutils literal notranslate"><span class="pre">MgrModule</span></code> instance.  This is an instance of <code class="docutils literal notranslate"><span class="pre">rados.Rados</span></code> which
has been constructed for you using the existing Ceph context (an internal
detail of the C++ Ceph code) of the mgr daemon.</p>
<p>Always use this specially constructed librados instance instead of
constructing one by hand.</p>
<p>Similarly, if you are using libcephfs to access the file system, then
use the libcephfs <code class="docutils literal notranslate"><span class="pre">create_with_rados</span></code> to construct it from the
<code class="docutils literal notranslate"><span class="pre">MgrModule.rados</span></code> librados instance, and thereby inherit the correct context.</p>
<p>Remember that your module may be running while other parts of the cluster
are down: do not assume that librados or libcephfs calls will return
promptly -- consider whether to use timeouts or to block if the rest of
the cluster is not fully available.</p>
</section>
<section id="id11">
<h2>备用模式的实现<a class="headerlink" href="#id11" title="Permalink to this heading"></a></h2>
<p>For some modules, it is useful to run on standby manager daemons as well
as on the active daemon.  For example, an HTTP server can usefully
serve HTTP redirect responses from the standby managers so that
the user can point his browser at any of the manager daemons without
having to worry about which one is active.</p>
<p>Standby manager daemons look for a subclass of <code class="docutils literal notranslate"><span class="pre">StandbyModule</span></code>
in each module.  If the class is not found then the module is not
used at all on standby daemons.  If the class is found, then
its <code class="docutils literal notranslate"><span class="pre">serve</span></code> method is called.  Implementations of <code class="docutils literal notranslate"><span class="pre">StandbyModule</span></code>
must inherit from <code class="docutils literal notranslate"><span class="pre">mgr_module.MgrStandbyModule</span></code>.</p>
<p>The interface of <code class="docutils literal notranslate"><span class="pre">MgrStandbyModule</span></code> is much restricted compared to
<code class="docutils literal notranslate"><span class="pre">MgrModule</span></code> -- none of the Ceph cluster state is available to
the module.  <code class="docutils literal notranslate"><span class="pre">serve</span></code> and <code class="docutils literal notranslate"><span class="pre">shutdown</span></code> methods are used in the same
way as a normal module class.  The <code class="docutils literal notranslate"><span class="pre">get_active_uri</span></code> method enables
the standby module to discover the address of its active peer in
order to make redirects.  See the <code class="docutils literal notranslate"><span class="pre">MgrStandbyModule</span></code> definition
in the Ceph source code for the full list of methods.</p>
<p>For an example of how to use this interface, look at the source code
of the <code class="docutils literal notranslate"><span class="pre">dashboard</span></code> module.</p>
</section>
<section id="id12">
<h2>模块间通信<a class="headerlink" href="#id12" title="Permalink to this heading"></a></h2>
<p>Modules can invoke member functions of other modules.</p>
<dl class="py method">
<dt class="sig sig-object py" id="mgr_module.MgrModule.remote">
<span class="sig-prename descclassname"><span class="pre">MgrModule.</span></span><span class="sig-name descname"><span class="pre">remote</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">module_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">method_name</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span><span class="n"><span class="pre">args</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">kwargs</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mgr_module.MgrModule.remote" title="Permalink to this definition"></a></dt>
<dd><p>Invoke a method on another module.  All arguments, and the return
value from the other module must be serializable.</p>
<p>Limitation: Do not import any modules within the called method.
Otherwise you will get an error in Python 2:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="ne">RuntimeError</span><span class="p">(</span><span class="s1">&#39;cannot unmarshal code objects in restricted execution mode&#39;</span><span class="p">,)</span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>module_name</strong> (<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>) -- Name of other module.  If module isn’t loaded,
an ImportError exception is raised.</p></li>
<li><p><strong>method_name</strong> (<code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>) -- Method name.  If it does not exist, a NameError
exception is raised.</p></li>
<li><p><strong>args</strong> (<code class="xref py py-data docutils literal notranslate"><span class="pre">Any</span></code>) -- Argument tuple</p></li>
<li><p><strong>kwargs</strong> (<code class="xref py py-data docutils literal notranslate"><span class="pre">Any</span></code>) -- Keyword argument dict</p></li>
</ul>
</dd>
<dt class="field-even">Raises<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>RuntimeError</strong> -- <strong>Any</strong> error raised within the method is converted to a RuntimeError</p></li>
<li><p><strong>ImportError</strong> -- No such module</p></li>
</ul>
</dd>
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><code class="xref py py-data docutils literal notranslate"><span class="pre">Any</span></code></p>
</dd>
</dl>
</dd></dl>

<p>Be sure to handle <code class="docutils literal notranslate"><span class="pre">ImportError</span></code> to deal with the case that the desired
module is not enabled.</p>
<p>If the remote method raises a python exception, this will be converted
to a RuntimeError on the calling side, where the message string describes
the exception that was originally thrown.  If your logic intends
to handle certain errors cleanly, it is better to modify the remote method
to return an error value instead of raising an exception.</p>
<p>At time of writing, inter-module calls are implemented without
copies or serialization, so when you return a python object, you’re
returning a reference to that object to the calling module.  It
is recommend <em>not</em> to rely on this reference passing, as in future the
implementation may change to serialize arguments and return
values.</p>
</section>
<section id="id13">
<h2>干净地关闭<a class="headerlink" href="#id13" title="Permalink to this heading"></a></h2>
<p>If a module implements the <code class="docutils literal notranslate"><span class="pre">serve()</span></code> method, it should also implement
the <code class="docutils literal notranslate"><span class="pre">shutdown()</span></code> method to shutdown cleanly: misbehaving modules
may otherwise prevent clean shutdown of ceph-mgr.</p>
</section>
<section id="id14">
<h2>局限性<a class="headerlink" href="#id14" title="Permalink to this heading"></a></h2>
<p>It is not possible to call back into C++ code from a module’s
<code class="docutils literal notranslate"><span class="pre">__init__()</span></code> method.  For example calling <code class="docutils literal notranslate"><span class="pre">self.get_module_option()</span></code> at
this point will result in an assertion failure in ceph-mgr.  For modules
that implement the <code class="docutils literal notranslate"><span class="pre">serve()</span></code> method, it usually makes sense to do most
initialization inside that method instead.</p>
</section>
<section id="debugging">
<h2>Debugging<a class="headerlink" href="#debugging" title="Permalink to this heading"></a></h2>
<p>Apparently, we can always use the <a class="reference internal" href="#mgr-module-dev-logging"><span class="std std-ref">日志记录</span></a> facility
for debugging a ceph-mgr module. But some of us might miss <a class="reference external" href="https://docs.python.org/3/library/pdb.html">PDB</a> and the
interactive Python interpreter. Yes, we can have them as well when developing
ceph-mgr modules! <code class="docutils literal notranslate"><span class="pre">ceph_mgr_repl.py</span></code> can drop you into an interactive shell
talking to <code class="docutils literal notranslate"><span class="pre">selftest</span></code> module. With this tool, one can peek and poke the
ceph-mgr module, and use all the exposed facilities in quite the same way
how we use the Python command line interpreter. For using <code class="docutils literal notranslate"><span class="pre">ceph_mgr_repl.py</span></code>,
we need to</p>
<ol class="arabic simple">
<li><p>ready a Ceph cluster</p></li>
<li><p>enable the <code class="docutils literal notranslate"><span class="pre">selftest</span></code> module</p></li>
<li><p>setup the necessary environment variables</p></li>
<li><p>launch the tool</p></li>
</ol>
<p>Following is a sample session, in which the Ceph version is queried by
inputting <code class="docutils literal notranslate"><span class="pre">print(mgr.version)</span></code> at the prompt. And later
<code class="docutils literal notranslate"><span class="pre">timeit</span></code> module is imported to measure the execution time of
<cite>mgr.get_mgr_id()</cite>.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span><span class="nb">cd</span><span class="w"> </span>build
<span class="gp">$ </span><span class="nv">MDS</span><span class="o">=</span><span class="m">0</span><span class="w"> </span><span class="nv">MGR</span><span class="o">=</span><span class="m">1</span><span class="w"> </span><span class="nv">OSD</span><span class="o">=</span><span class="m">3</span><span class="w"> </span><span class="nv">MON</span><span class="o">=</span><span class="m">1</span><span class="w"> </span>../src/vstart.sh<span class="w"> </span>-n<span class="w"> </span>-x
<span class="gp">$ </span>bin/ceph<span class="w"> </span>mgr<span class="w"> </span>module<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>selftest
<span class="gp">$ </span>../src/pybind/ceph_mgr_repl.py<span class="w"> </span>--show-env
<span class="gp">   $ </span><span class="nb">export</span><span class="w"> </span><span class="nv">PYTHONPATH</span><span class="o">=</span>/home/me/ceph/src/pybind:/home/me/ceph/build/lib/cython_modules/lib.3:/home/me/ceph/src/python-common:<span class="nv">$PYTHONPATH</span>
<span class="gp">   $ </span><span class="nb">export</span><span class="w"> </span><span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span>/home/me/ceph/build/lib:<span class="nv">$LD_LIBRARY_PATH</span>
<span class="gp">$ </span><span class="nb">export</span><span class="w"> </span><span class="nv">PYTHONPATH</span><span class="o">=</span>/home/me/ceph/src/pybind:/home/me/ceph/build/lib/cython_modules/lib.3:/home/me/ceph/src/python-common:<span class="nv">$PYTHONPATH</span>
<span class="gp">$ </span><span class="nb">export</span><span class="w"> </span><span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span>/home/me/ceph/build/lib:<span class="nv">$LD_LIBRARY_PATH</span>
<span class="gp">$ </span>../src/pybind/ceph_mgr_repl.py
<span class="gp">$ </span>../src/pybind/ceph_mgr_repl.py
<span class="go">Python 3.9.2 (default, Feb 28 2021, 17:03:44)</span>
<span class="go">[GCC 10.2.1 20210110] on linux</span>
<span class="go">Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.</span>
<span class="gp gp-VirtualEnv">(MgrModuleInteractiveConsole)</span>
<span class="go">[mgr self-test eval] &gt;&gt;&gt; print(mgr.version)</span>
<span class="go">ceph version Development (no_version) quincy (dev)</span>
<span class="go">[mgr self-test eval] &gt;&gt;&gt; from timeit import timeit</span>
<span class="go">[mgr self-test eval] &gt;&gt;&gt; timeit(mgr.get_mgr_id)</span>
<span class="go">0.16303414600042743</span>
<span class="go">[mgr self-test eval] &gt;&gt;&gt;</span>
</pre></div>
</div>
<p>If you want to “talk” to a ceph-mgr module other than <code class="docutils literal notranslate"><span class="pre">selftest</span></code> using
this tool, you can either add a command to the module you want to debug
exactly like how <code class="docutils literal notranslate"><span class="pre">mgr</span> <span class="pre">self-test</span> <span class="pre">eval</span></code> command was added to <code class="docutils literal notranslate"><span class="pre">selftest</span></code>. Or
we can make this simpler by promoting the <code class="docutils literal notranslate"><span class="pre">eval()</span></code> method to a dedicated
<a class="reference external" href="_https://en.wikipedia.org/wiki/Mixin">Mixin</a> class and inherit your <code class="docutils literal notranslate"><span class="pre">MgrModule</span></code> subclass from it. And define
a command with it. Assuming the prefix of the command is <code class="docutils literal notranslate"><span class="pre">mgr</span> <span class="pre">my-module</span> <span class="pre">eval</span></code>,
one can just put</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><style type="text/css">
span.prompt1:before {
  content: "$ ";
}
</style><span class="prompt1">../src/pybind/ceph_mgr_repl.py<span class="w"> </span>--prefix<span class="w"> </span><span class="s2">&quot;mgr my-module eval&quot;</span></span>
</pre></div></div></section>
<section id="id15">
<h2>还有未竟事宜否？<a class="headerlink" href="#id15" title="Permalink to this heading"></a></h2>
<p>The ceph-mgr python interface is not set in stone.  If you have a need
that is not satisfied by the current interface, please bring it up
on the ceph-devel mailing list.  While it is desired to avoid bloating
the interface, it is not generally very hard to expose existing data
to the Python code when there is a good reason.</p>
</section>
</section>



<div id="support-the-ceph-foundation" class="admonition note">
  <p class="first admonition-title">Brought to you by the Ceph Foundation</p>
  <p class="last">The Ceph Documentation is a community resource funded and hosted by the non-profit <a href="https://ceph.io/en/foundation/">Ceph Foundation</a>. If you would like to support this and our other efforts, please consider <a href="https://ceph.io/en/foundation/join/">joining now</a>.</p>
</div>


           </div>
           
          </div>
          <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
        <a href="../administrator/" class="btn btn-neutral float-left" title="ceph-mgr 管理员指南" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
        <a href="../orchestrator_modules/" class="btn btn-neutral float-right" title="ceph-mgr orchestrator 模块" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
    </div>

  <hr/>

  <div role="contentinfo">
    <p>&#169; Copyright 2016, Ceph authors and contributors. Licensed under Creative Commons Attribution Share Alike 3.0 (CC-BY-SA-3.0).</p>
  </div>

   

</footer>
        </div>
      </div>

    </section>

  </div>
  

  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script>

  
  
    
   

</body>
</html>